# -*- coding: utf-8 -*- 
import asyncio 
import http.cookies 
import random 
import pandas as pd 
import atexit
import datetime
import time
import os
import signal
import sys
from typing import * 

import aiohttp 
import blivedm 
import blivedm.models.web as web_models 
import blivedm.live_data.live_data as live_data
import blivedm.date_recorder.date_recorder as DailyRecorder 
import blivedm.utils as utils

# 直播间ID的取值看直播间URL
TEST_ROOM_IDS = [192, 26427138, 25889861, 1960174983, 21479369]
DO_NOT_SEND_COMMENT_ROOM_IDS = [192, 1960174983]
# TEST_ROOM_IDS = [21479369]
ROOM_ID_TO_NAME = {192: "钉宫妮妮Ninico", 26427138: "伊菲不是小火驴", 25889861:"立夏licca", 21479369:"山葚", 1960174983:"希晨Hitchen"}
NAME_TO_ROOM_ID = {"伊菲不是小火驴": 26427138}
# 这里填一个已登录账号的cookie的SESSDATA字段的值
SESSDATA = 'e3fd2266%2C1765710583%2Ccd77d%2A62CjDQ76OMeKb6a88VIhYvyer1hhjMvmVB4J9Ze7R8LJceYglHuMWWzmiwjImcu5TGNOUSVnFLOFF6OHYwNmhjU2dmOEpGcHlJS2N3eFNWbm1EbDRQYnJGeHFtV2xrck85TlE0S1d4MmtfVnhDUkRDMFRKeXdrSmJjQTlHVXJPWENncW5rcldkbXF3IIEC'

class web_monitor:
    def __init__(self, room_ids: List[int], sessdata: str = SESSDATA):
        self.room_ids = room_ids
        self.sessdata = sessdata
        self.session: Optional[aiohttp.ClientSession] = None
        self.date_change_recorder = DailyRecorder.DailyRecorder(0,30,0)
        self.night_snack_recorder = DailyRecorder.DailyRecorder(23,0,0)
        self.scheduler_task = None
        self.live_data:Dict[int, live_data.live_data]  = {}
        self.clients:Dict[int, blivedm.BLiveClient] = {}
        self.name:Dict[int, Union[str, int]] = {}
        for roomid in room_ids:
            self.live_data[roomid] = live_data()

    async def init_session(self):
        cookies = http.cookies.SimpleCookie()
        cookies['SESSDATA'] = self.sessdata
        cookies['SESSDATA']['domain'] = 'bilibili.com'
        
        self.session = aiohttp.ClientSession()
        self.session.cookie_jar.update_cookies(cookies)

    async def run_clients(self):
        clients = []
        for room_id in self.room_ids:
            if room_id in ROOM_ID_TO_NAME:
                self.name[room_id] = ROOM_ID_TO_NAME[room_id]
            clients.append(blivedm.BLiveClient(room_id, session=self.session, name=self.name.get(room_id)))
        # clients = [blivedm.BLiveClient(room_id, session=self.session) for room_id in self.room_ids]
        handler = self.MyHandler(self)
        for i in range(len(clients)):
            client = clients[i]
            self.clients[self.room_ids[i]] = client
            client.set_handler(handler)
            client.start()
        
        try:
            await asyncio.gather(*(client.join() for client in clients))
        finally:
            await asyncio.gather(*(client.stop_and_close() for client in clients))

    async def start(self):
        await self.init_session()
        self.scheduler_task = asyncio.create_task(self.dateScheduler_loop())
        try:
            await self.run_clients()
        finally:
            await self.session.close()
            self.scheduler_task.cancel()

    class MyHandler(blivedm.BaseHandler):
        def __init__(self, monitor : 'web_monitor'):
            super().__init__()
            self.monitor = monitor
            self.message_handler = blivedm.MessageHandler()
        # 演示如何添加自定义回调
        # _CMD_CALLBACK_DICT = blivedm.BaseHandler._CMD_CALLBACK_DICT.copy()
        #
        # # 看过数消息回调
        # def __watched_change_callback(self, client: blivedm.BLiveClient, command: dict):
        #     print(f'[{client.room_id}] WATCHED_CHANGE: {command}')
        # _CMD_CALLBACK_DICT['WATCHED_CHANGE'] = __watched_change_callback  # noqa

        def _on_heartbeat(self, client: blivedm.BLiveClient, message: web_models.HeartbeatMessage):
            print(f'[{client.original_room_id}] 心跳')

        def _on_danmaku(self, client: blivedm.BLiveClient, message: web_models.DanmakuMessage):
            try:
                if client.original_room_id not in DO_NOT_SEND_COMMENT_ROOM_IDS:
                    if message.uname == "伊菲家的小助手":
                        time.sleep(1)
                    if message.msg == "查询盲盒":
                        danmu = self.message_handler.callback(message.msg, message.uname, self.monitor.live_data[client.original_room_id].get_manghe())
                        asyncio.create_task(self._async_send_danmu(client, danmu, message.uid))
                        print(danmu)
                    elif message.msg == "查询房间盲盒":
                        danmu = self.message_handler.callback(message.msg, self.monitor.live_data[client.original_room_id].get_manghe())
                        asyncio.create_task(self._async_send_danmu(client, danmu, message.uid))
                        print(danmu)
            except Exception as e:
                print(f"捕获到异常: {type(e).__name__}: {e}")
                # raise  # 可选择重新抛出异常
            finally:
                """不做任何操作"""
            print(f'[{client.original_room_id}] {message.uname}：{message.msg}')

        def _on_gift(self, client: blivedm.BLiveClient, message: web_models.GiftMessage):
            if message.original_gift_id != 0:
                self.monitor.live_data[client.original_room_id].recieve_manghe(
                    message.uname, message.num, message.original_gift_name, message.original_gift_price / 1000, message.gift_name, message.price / 1000, message.timestamp)
                print(f'[{client.original_room_id}] {message.uname} 赠送{message.original_gift_name}'
                      f' 爆出{message.gift_name}x{message.num}'
                      f' （{message.coin_type}瓜子x{message.price * message.num}）')
            else:
                self.monitor.live_data[client.original_room_id].recieve_gift(message.uname, message.num, message.gift_name, message.price / 1000, message.timestamp)
                print(f'[{client.original_room_id}] {message.uname} 赠送{message.gift_name}x{message.num}'
                      f' （{message.coin_type}瓜子x{message.price * message.num}）')

        def _on_user_toast_v2(self, client: blivedm.BLiveClient, message: web_models.UserToastV2Message):
            guard_type = ''
            if message.guard_level == 3:
                guard_type = '舰长'
            elif message.guard_level == 2:
                guard_type = '提督'
            elif message.guard_level == 1:
                guard_type = '总督'
            guard_num = ''
            if message.unit != '月':
                guard_num = message.unit
            else:
                guard_num = str(message.num) + message.unit
            # print(message)
            self.monitor.live_data[client.original_room_id].recieve_guard(message.username, guard_type, guard_num, message.price / 1000, 
                                                                                                        message.toast_msg, message.start_time)
            print(f'[{client.original_room_id}] {message.username} 上舰，guard_level={message.guard_level}')

        def _on_super_chat(self, client: blivedm.BLiveClient, message: web_models.SuperChatMessage):
            self.monitor.live_data[client.original_room_id].recieve_superchat(message.uname, message.price, message.message, message.start_time)
            print(f'[{client.original_room_id}] 醒目留言 ¥{message.price} {message.uname}：{message.message}')

        async def _async_send_danmu(self, client: blivedm.BLiveClient, danmu: str, uid: int = None):
            await client.send_danmu(danmu) if uid is None else await client.send_danmu(danmu, uid)

    async def date_change_callback(self, date: str):
        print(date)
        year, month, day, hour, minute = date.split('-')
        print(f"开始处理日期: {year}-{month}-{day}-{hour}")

        if int(hour) < self.date_change_recorder.get_target_hour():
            actual_date = utils.get_yesterday(date)
            year, month, day, hour, minute = actual_date.split('-')

        # 按房间分组处理任务
        for room_id in self.room_ids:
            import sys
            live_data = self.live_data[room_id]
            client_name = self.clients[room_id].name

            if utils.which_system() == 'linux':
                file_path = f"/home/data/{client_name}/{year}年{month}月/"
                await utils.async_ensure_path_exists(file_path)
                print("当前是Linux系统")
            elif utils.which_system() == 'windows':
                file_path = ""
                print("当前是Windows系统")
            else:
                print("其他操作系统")

            captain_path = file_path + f"[{client_name}]{year}年{month}月舰长列表.xlsx"
            
            # 每日礼物处理(顺序执行)
            gift_path = file_path + f"[{client_name}]{year}年{month}月{day}日礼物列表.xlsx"
            
            # 1. 处理SC消息
            sc_df = await live_data.transfer_superchat()
            await utils.async_write_df_to_excel(sc_df, gift_path, "superchat")
            
            # 2. 处理普通礼物
            gift_df = await live_data.transfer_gift()
            await utils.async_write_df_to_excel(gift_df, gift_path, "礼物")
            
            # 3. 处理盲盒礼物
            manghe_df = await live_data.transfer_manghe()
            await utils.async_write_df_to_excel(manghe_df, gift_path, "盲盒礼物")
            
            # 4. 处理舰长数据
            guard_df = await live_data.transfer_guard()
            await utils.async_write_df_to_excel(guard_df, gift_path, "大航海")
            await utils.async_write_df_to_excel(guard_df, captain_path, "大航海")
        
        print(f"完成日期处理: {year}-{month}-{day}")

    async def night_snack_callback(self, date: str):
        client = self.clients[NAME_TO_ROOM_ID["伊菲不是小火驴"]]
        await client.send_danmu(["小助手友情提醒，该点夜宵啦！"])

    async def dateScheduler_loop(self):
        self.date_change_recorder.add_callback(self.date_change_callback)
        self.date_change_recorder.start()
        self.night_snack_recorder.add_callback(self.night_snack_callback)
        self.night_snack_recorder.start()
        try:
            while True:
                await asyncio.sleep(3600)
        except asyncio.CancelledError:
            print("Task cancelled, stopping recorder...")
            await self.date_change_recorder.stop()
        except Exception as e:
            print(f"Unexpected error: {e}")
            raise

if __name__ == '__main__':
    monitor = web_monitor(TEST_ROOM_IDS, SESSDATA)
    try:
        if os.path.exists('app.log'):
            os.remove('app.log')
            print("app.log文件已成功删除")
    except:
        print("applog删除失败，但继续")
    try:
        asyncio.run(monitor.start())
    finally:
        asyncio.run(monitor.date_change_callback(datetime.datetime.now().strftime("%Y-%m-%d-%H-%M")))

    

    